In the object-oriented paradigm, all tasks are performed by objects, which include attributes that hold information and methods that accomplish tasks and interact with other objects. Each object is an instance of a class that defines the object's attributes and methods. Some classes (hereinafter, "containers"), need to interact with many different types of classes (hereinafter, "contained"). For example, in an application that has a graphical user interface, a object that is an instance of a particular container class (e.g., a "DoSomething" class) might need to interact with the individual objects that correspond to the GUI components, each of which could be an instance of a different GUI component class. Conventionally, there are three ways a container class can refer to the contained classes.
In a first way, the container class includes specialized methods that perform specific operations on specific classes. Each of these methods has a unique name. For example, assuming that the DoSomething class can be used to add text field, list and vector GUI components to a GUI, the DoSomething class, written in the Java.TM. programming language (Java and all Java-based trademarks and logos are trademarks or registered trademarks of Sun Microsystems, Inc. in the United States and other countries), might look as shown in Table 1:
TABLE 1 public class DoSomething { public DoSomething (){ // constructor code for the DoSomething class } public void includeTextField (TextField tf) { // code that adds a text field component } public void includeList (List I) { // code that adds a list component } public void includeVector (Vector v) { // code that adds a vector component } }
Syntax of the Java.TM. programming language is well-known; however, because examples in the Java.TM. programming language are used throughout this document, a few of the statements above are now described. The first statement, "public DoSomething( )" declares a constructor method that is invoked by a programmer whenever they wish to create another object instance of the DoSomething object class. All Java.TM. programming language classes have constructors, whose name is the same as the associated class. The actual constructor method code is not shown, but is referred to in the comment, "// constructor code for the DoSomething class". The second statement, "include TextField(TextField tf)" declares a specialized method that is invoked whenever a programmer wishes to add a TextField GUI component to an application GUI. Subsequent statements are declarations for similar methods for adding the other types of GUI components. This form of container is not commonly used as it results in a very large API (Application Programming Interface) due to the proliferation of public methods for manipulating different types of GUI components. For more information on the Java.TM. programming language syntax, refer to Patrick Niemeyer & Joshua Peck, "Exploring Java,"(2nd ed. 1997), which is entirely incorporated herein by reference.
In a second way, referred to as overloading, the container class provides unique methods to handle the contained classes, but assigns the same name to methods that accomplish the same goal. For example, using overloading, the DoSomething class, written in the Java.TM. programming language, might look as shown in Table 2:
TABLE 2 public class DoSomething { public DoSomething (){ // constructor code for the DoSomething class } public void include (TextField tf) { // code that adds a text field component } public void include (List I) { // code that adds a list component } public void include (Vector v) { // code that adds a vector component } }
Given such a container class a programmer can add any type of supported GUI component by simply issuing a call to DoSomething.include (ob), where ob is an object of a supported class. The Java.TM. programming language compiler then automatically uses whichever include method corresponds to the class of ob. Overloading is the most commonly used technique for handling contained classes because it reduces the size of the API without needing the if-then-else clauses employed by the third way, which is now described.
In the third way, the container class provides a general method that can handle objects of any of the supported contained classes. Such general methods employ if-then-else clauses to determine which code to apply, based on the class of the object passed to the method. For example, using general methods, the DoSomething class, written in the Java.TM. programming language, might look as shown in Table 3:
TABLE 3 public class DoSomething { public DoSomething (){ // constructor code for the DoSomething class } public void include (Object ob) { if (ob instanceof TextField) { // code that adds a text field component } else if (ob instanceof List) { // code that adds a list component } else if (ob instanceof Vector) { // code that adds a vector component } } }
With a container class implemented in this way a programmer can add any type of supported GUI component by simply issuing a call to DoSomething.include (arg), where arg is an object instance of a supported class. In contrast to the second way, the if-then-else clause selects the correct code based on the class of the object arg. Using an if-then-else clause allows the API to be simplified but, due to the additional statements, adds to the size of the container class and instances thereof. For this reason, this technique is not as widely used as the overloading method.
Problems with each of these methods arise when the container class needs to support another type of contained object (e.g., a RadioButton component). When this need arises, the container object needs to be completely recoded to include the new class. This is because each container includes all of the code it needs to handle the contained classes. For example, in the first case, a new includeRadioButton (RadioButton rb) method would need to be added to the container class, in the second case a new include (RadioButton rb) method would need to be added, and in the third case a new else if (ob instanceof RadioButton) statement and associated code would need to be added.
The requirement of adding new code to existing classes results in extended product release dates and testing to ensure that the new classes are operable (even if support for only one new class is added to an existing container). Therefore, there is a need for technology that enables support for new classes to be added to a container class that does not require modification or recoding of the container class.